package com.lcy.web.generator;

import com.jfinal.kit.JavaKeyword;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.generator.*;
import com.jfinal.plugin.c3p0.C3p0Plugin;

import javax.sql.DataSource;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.ResourceBundle;

/**
 * Created by loucunyin on 2017/1/12 0012.
 * 用于生成 SQL bean
 */
public class SqlBeanGenerator {

    public static void main(String[] args) {
        ResourceBundle bundle = ResourceBundle.getBundle("res/generator/SqlModel");

        String jdbcUrl = bundle.getString("jdbcUrl");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        String sqlBeanPackageName = bundle.getString("sqlBeanPackageName");
        String sqlBeanOutputDir = bundle.getString("sqlBeanOutputDir");

        String[] strings = {jdbcUrl, user, password, sqlBeanPackageName, sqlBeanOutputDir};
        for (String string : strings) {
            System.out.println(string);
            if (string == null || string.isEmpty()) {
                throw new RuntimeException("参数不完整");
            }
        }

        C3p0Plugin c3p0Plugin = new C3p0Plugin(jdbcUrl, user, password);
        c3p0Plugin.start();
        SqlBeanGenerator sqlBeanGenerator = new SqlBeanGenerator(c3p0Plugin.getDataSource(), sqlBeanPackageName, sqlBeanOutputDir);
        sqlBeanGenerator.generate();
        c3p0Plugin.stop();
    }

    private MetaBuilder mMetaBuilder;

    SqlBeanGenerator(DataSource dataSource, String packageName, String outputDir) {
        baseModelPackageName = packageName;
        baseModelOutputDir = outputDir;
        mMetaBuilder = new MetaBuilder(dataSource);
    }

    protected String packageTemplate =
            "package %s;%n%n";
    protected String importTemplate =
            "import com.google.gson.annotations.SerializedName;%n";
    protected String classDefineTemplate =
            "/**%n" +
                    " * Generated by loucunyin.%n" +
                    " */%n" +
                    "public class %s {%n%n";

    protected String memberTemplate = "\t@SerializedName(\"%s\")%n" +
            "\tprivate %s %s;%n";
    protected String setterTemplate =
            "\tpublic void %s(%s %s) {%n" +
                    "\t\t%s = %s;%n" +
                    "\t}%n%n";
    protected String getterTemplate =
            "\tpublic %s %s() {%n" +
                    "\t\treturn %s;%n" +
                    "\t}%n%n";

    protected String baseModelPackageName;
    protected String baseModelOutputDir;

    protected JavaKeyword javaKeyword = new JavaKeyword();


    public void generate() {
        List<TableMeta> tableMetas = mMetaBuilder.build();
        System.out.println("Generate base model ...");
        for (TableMeta tableMeta : tableMetas)
            genBaseModelContent(tableMeta);
        wirtToFile(tableMetas);
    }

    protected void genBaseModelContent(TableMeta tableMeta) {
        StringBuilder ret = new StringBuilder();
        genPackage(ret);
        genImport(ret);
        genClassDefine(tableMeta, ret);
        genMembers(tableMeta, ret);
        for (ColumnMeta columnMeta : tableMeta.columnMetas) {
            genSetMethodName(columnMeta, ret);
            genGetMethodName(columnMeta, ret);
        }
        ret.append(String.format("}%n"));
        tableMeta.baseModelContent = ret.toString();
    }

    protected void genPackage(StringBuilder ret) {
        ret.append(String.format(packageTemplate, baseModelPackageName));
    }

    protected void genImport(StringBuilder ret) {
        ret.append(String.format(importTemplate));
    }

    protected void genClassDefine(TableMeta tableMeta, StringBuilder ret) {
        ret.append(String.format(classDefineTemplate, tableMeta.modelName + "Bean"));
    }

    protected void genMembers(TableMeta tableMeta, StringBuilder ret) {
        for (ColumnMeta columnMeta : tableMeta.columnMetas) {
            genMember(columnMeta, ret);
        }
    }

    protected void genMember(ColumnMeta columnMeta, StringBuilder ret) {
        String memberName = "m" + StrKit.firstCharToUpperCase(columnMeta.attrName);
        String member = String.format(memberTemplate, columnMeta.attrName, columnMeta.javaType, memberName);
        ret.append(member);
    }

    protected void genSetMethodName(ColumnMeta columnMeta, StringBuilder ret) {
        String setterMethodName = "set" + StrKit.firstCharToUpperCase(columnMeta.attrName);
        String memberName = "m" + StrKit.firstCharToUpperCase(columnMeta.attrName);
        // 如果 setter 参数名为 java 语言关键字，则添加下划线前缀 "_"
        String argName = javaKeyword.contains(columnMeta.attrName) ? "_" + columnMeta.attrName : columnMeta.attrName;
        String setter = String.format(setterTemplate, setterMethodName, columnMeta.javaType, argName, memberName, argName);
        ret.append(setter);
    }

    protected void genGetMethodName(ColumnMeta columnMeta, StringBuilder ret) {
        String getterMethodName = "get" + StrKit.firstCharToUpperCase(columnMeta.attrName);
        String memberName = "m" + StrKit.firstCharToUpperCase(columnMeta.attrName);
        String getter = String.format(getterTemplate, columnMeta.javaType, getterMethodName, memberName);
        ret.append(getter);
    }

    protected void wirtToFile(List<TableMeta> tableMetas) {
        try {
            for (TableMeta tableMeta : tableMetas)
                wirtToFile(tableMeta);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * base model 覆盖写入
     */
    protected void wirtToFile(TableMeta tableMeta) throws IOException {
        File dir = new File(baseModelOutputDir);
        if (!dir.exists())
            dir.mkdirs();

        String target = baseModelOutputDir + File.separator + tableMeta.modelName + "Bean.java";
        FileWriter fw = new FileWriter(target);
        try {
            fw.write(tableMeta.baseModelContent);
        } finally {
            fw.close();
        }
    }
}
